home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 076-100 / disk_087 / memwatch / memwatch.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  14KB  |  354 lines

  1. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  2. /* |_o_o|\\ Copyright (c) 1986 The Software Distillery.  All Rights Reserved */
  3. /* |. o.| || This program may not be distributed without the permission of   */
  4. /* | .  | || the authors.                                                    */
  5. /* | o  | ||   Dave Baker    Ed Burnette        Stan Chow          BBS:      */
  6. /* |  . |//    Jay Denebeim  Gordon Keener      Jack Rouse   (919)-471-6436  */
  7. /* ======      John Toebes   Mary Ellen Toebes  Doug Walker                  */
  8. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  9. /* This program watches the first 0x100 bytes of memory for random trashing, */
  10. /* attempts repair of the damage and then puts up an alert indicating the    */
  11. /* damage that was done.  Many thanks to EA for suggesting this program at   */
  12. /* the developer's conference.                                               */
  13. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  14.  
  15. /* * * * * * * * * INCLUDE FILES * * * * * * * * * * * */
  16. #include <exec/types.h>
  17. #include <exec/nodes.h>
  18. #include <exec/lists.h>
  19. #include <exec/memory.h>
  20. #include <exec/ports.h>
  21. #include <exec/libraries.h>
  22. #include <exec/io.h>
  23. #include <exec/tasks.h>
  24. #include <exec/execbase.h>
  25. #include <exec/devices.h>
  26. #include <devices/timer.h>
  27. #include <intuition/intuition.h>
  28. #include <libraries/dosextens.h>
  29. #include <proto/dos.h>
  30. #include <proto/intuition.h>
  31. #include <proto/exec.h>
  32.  
  33. /* * * * * * * * * * * STRUCTURES * * * * * * * * * * * * */
  34. typedef struct stomped
  35.    {
  36.    long data;           /* value that was thrown into address wildly */
  37.    long address;        /* address that was changed */
  38.    } STOMPED;
  39.  
  40. struct MsgPort *CreatePort();
  41. void DeletePort();
  42.  
  43. struct OURMSG {
  44.  struct Message msgpart;
  45.  int interval;
  46.  };
  47.  
  48. /* * * * * * * * * * * CONSTANTS * * * * * * * * * * * * */
  49. #define TIMEINTERVAL 2500L      /* in micro seconds */
  50. #define LOWLIMIT     20L        /* smallest safe interval */
  51. #define BANNER "\x9B0;33mMemWatch II\x9B0m by John Toebes - Copyright \xa9 1987 The Software Distillery\n 235 Trillingham Lane, Cary NC 27513   BBS:(919)-471-6436\n"
  52. #define BANNER1 "Usage: \x9B1mMemWatch\x9B0m [n]  - set interval between watch checks (Default 2500ms)\n       \x9B1mMemWatch\x9B0m QUIT - To terminate MemWatch\n"
  53. #define PORTNAME "MemWatch_port"
  54. #define KILLMSG "Terminating MemWatch\n"
  55.  
  56. /* * * * * * * * * * * EXTERNAL ROUTINES * * * * * * * * * */
  57. struct IntuitionBase *IntuitionBase = NULL;
  58. extern void SaveMem();
  59. extern int ValidateMem(struct stomped *);
  60.  
  61. struct DosLibrary *DOSBase;
  62. int MathTransBase, MathBase;
  63.  
  64. /* Declarations for CBACK */
  65. extern long _Backstdout;         /* standard output when run in background */
  66. long _BackGroundIO = 1;          /* Flag to tell it we want to do I/O      */
  67. long _stack = 4000;              /* Amount of stack space our task needs   */
  68. char *_procname = "MemWatch II"; /* The name of the task to create         */
  69. long _priority = 20;             /* The priority to run us at              */
  70.  
  71. /* * * * * * * * * * * Alert definition structure* * * * * * * * * */
  72. /* we want to display the message:                                 */
  73. /*  MemWatch II - Copyright c 1987 By the Software Distillery      */
  74. /* Someone stepped on Low memory $nnnnnnnn with $nnnnnnnn cccc!    */
  75. /*                                                                 */
  76. /* Left Button to correct location       Right button to continue  */
  77. /* 345678901234567890123456789012345678901234567890123456789012    */
  78. /*        11111111112222222222333333333344444444445555555555666    */
  79. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  80. #define ALERTHEIGHT 41          /* height of alert in pixals */
  81. #define ADDR_OFF 96             /* location of address substitution */
  82. #define DATA_OFF 111        /* Location of data val substitution */
  83. #define CHAR_OFF 120        /* Location of data text substitution */
  84. static char AlertString[] = {
  85. 0, 92,                          /* 2 byte x absolute offset of first string */
  86. 10,                             /* 1 byte y absolute offset of first string */
  87. 'M', 'e', 'm', 'W', 'a', 't', 'c', 'h', ' ', 'I', 'I', ' ',
  88. '-', ' ',
  89. 'C', 'o', 'p', 'y', 'r', 'i', 'g', 'h', 't',
  90. ' ', '\xa9', ' ', '1', '9', '8', '7', ' ',
  91. 'B', 'y', ' ',
  92. 'T', 'h', 'e', ' ',
  93. 'S', 'o', 'f', 't', 'w', 'a', 'r', 'e', ' ',
  94. 'D', 'i', 's', 't', 'i', 'l', 'l', 'e', 'r', 'y',
  95. 0,                                              /* null terminator on string */
  96. 1,                              /* flag to indicate another alert string */
  97. 0, 84,                          /* 2 byte x absolute offset of next string  */
  98. 18,                             /* 1 byte y absolute offset of next string  */
  99. 'S', 'o', 'm', 'e', 'o', 'n', 'e', ' ',                  /* message string  */
  100. 'S', 't', 'e', 'p', 'p', 'e', 'd', ' ',
  101. 'o', 'n', ' ', 'L', 'o', 'w', ' ',
  102. 'm', 'e', 'm', 'o', 'r', 'y', ' ',
  103. '$', 'h', 'h', 'h', 'h', 'h', 'h', 'h', 'h', ' ', /* address we substitute */
  104. 'w', 'i', 't', 'h', ' ',
  105. '$', 'h', 'h', 'h', 'h', 'h', 'h', 'h', 'h', ' ', /* data we substitute */
  106. 'c', 'c', 'c', 'c', '!',                          /* chars we substitute */
  107. 0,                                              /* null terminator on string */
  108. 1,                              /* flag to indicate another alert string */
  109. 0, 76,                         /* 2 byte x absolute offset of second string */
  110. 34,                             /* 1 byte y absolute offset of second string */
  111. 'L', 'e', 'f', 't', ' ',                /* second message string */
  112. 'B', 'u', 't', 't', 'o', 'n', ' ',
  113. 't', 'o', ' ',
  114. 'c', 'o', 'r', 'r', 'e', 'c', 't', ' ',
  115. 'l', 'o', 'c', 'a', 't', 'i', 'o', 'n',
  116. ' ', ' ', ' ', ' ', ' ', ' ', ' ',
  117. 'R', 'i', 'g', 'h', 't', ' ',
  118. 'b', 'u', 't', 't', 'o', 'n', ' ',
  119. 't', 'o', ' ',
  120. 'c', 'o', 'n', 't', 'i', 'n', 'u', 'e', 
  121. 0,                                              /* null terminator on string */
  122. 0 };                            /* flag to indicate no more strings */
  123.  
  124. /************************************************************************/
  125. /* The main program to watch the memory                                 */
  126. /************************************************************************/
  127. void _main(cmd)
  128. char *cmd;
  129.    {
  130.    struct MsgPort *port;
  131.    int stay = 0;
  132.    struct OURMSG *msg;
  133.  
  134.    register struct timerequest *timerreq = NULL;
  135.                                     /* request structure for timer waits*/
  136.    struct stomped rslt;             /* information on memory stomps */
  137.    register int i;                  /* general index variable */
  138.    register long v;                 /* temporary for formatting display */
  139.    register long interval = TIMEINTERVAL;
  140.                                     /* how long to wait between checks */
  141.    register char *p;                /* display formatting index */
  142.  
  143.    /* NOTE: The declarations for i anv v MUST come before that of interval */
  144.    /* because DOIO trashes D6 and D7 which are the first ones selected for */
  145.    /* register variables.  It doesn't matter if i and v are trashed but    */
  146.    /* interval MUST be maintained across the lifetime of the loop          */
  147.  
  148.    /* now see if we are already installed */
  149.    if ((port = FindPort(PORTNAME)) == NULL)
  150.       {
  151.       stay = 1; /* remember to hang around when we are done */
  152.       /* not installed, we need to install our own port */
  153.       if ((port = CreatePort(PORTNAME,0)) == NULL)
  154.          goto quitit;
  155.       }
  156.  
  157.    /* now send the parameter to the waiting program */
  158.    if ((msg = (struct OURMSG *)
  159.               AllocMem(sizeof(struct OURMSG), MEMF_CLEAR|MEMF_PUBLIC)) == NULL)
  160.       {
  161.       if (stay) DeletePort(port);
  162.          goto quitit;
  163.       }
  164.  
  165.    /* fill in the message information */
  166.    msg->msgpart.mn_Length = sizeof(struct OURMSG);
  167.  
  168.    /* if we were run from CLI then output our banner and process parameters */
  169.    if (cmd && *cmd)
  170.       {
  171.       /* display our copyright */
  172.       if (stay && _Backstdout)
  173.          Write(_Backstdout, BANNER, sizeof(BANNER));
  174.  
  175.       /* skip over any leading spaces in the command line */
  176.       while(*cmd != ' ')
  177.          cmd++;
  178.       while(*cmd == ' ')
  179.          cmd++;
  180.  
  181.       /* now see if they gave us a number to control the interval of checking */
  182.       interval = 0;
  183.  
  184.       while ((*cmd >= '0') && (*cmd <= '9'))
  185.          /* Multiply it by 10 without using a subroutine */
  186.          interval = (((interval << 2) + interval) << 1) + *cmd++ - '0';
  187.  
  188.       /* if they gave us nothing (or something we didn't parse well */
  189.       /* such as a VERY large number or just plain trash, give them a */
  190.       /* short usage message for the program */
  191.       if (!stricmp(cmd, "QUIT\n"))
  192.          {
  193.          interval = -1;
  194.          if (_Backstdout)
  195.             Write(_Backstdout, KILLMSG, sizeof(KILLMSG));
  196.          }
  197.       else
  198.          {
  199.          if (_Backstdout && (interval <= 0))
  200.             Write(_Backstdout, BANNER1, sizeof(BANNER1));
  201.          /* just incase we got a very low number (or a 0) from the command   */
  202.          /* line apply a minimum rule to keep from killing the system        */
  203.          /* performance note that since tasks switch at about every 20mili   */
  204.          /* seconds or so (not sure where that information is from) making it*/
  205.          /* less than 20000 really isn't much of a gain (but it feels nice)  */
  206.          if (interval < LOWLIMIT) interval = LOWLIMIT;
  207.          }
  208.       }
  209.    else
  210.       interval = 0;
  211.  
  212.    msg->interval = interval;
  213.  
  214.    PutMsg(port,msg);
  215.  
  216.    if (!stay)
  217.       {
  218. quitit:
  219.       if (_Backstdout)
  220.          Close(_Backstdout);
  221.       _Backstdout = 0;
  222.       XCEXIT(1);
  223.       }
  224.  
  225.    if (_Backstdout)
  226.       Close(_Backstdout);
  227.  
  228.    /* open up intuition - we only use this for the alert but we must do it */
  229.    /* anyway */
  230.    if ((IntuitionBase = (struct IntuitionBase *)
  231.                         OpenLibrary("intuition.library", 0)) == NULL)
  232.       goto abort;
  233.  
  234.    /* create a request structure to send the messages with */
  235.    if ((timerreq = (struct timerequest *)
  236.                     AllocMem(sizeof(struct timerequest),
  237.                              MEMF_CLEAR | MEMF_PUBLIC)) == NULL)
  238.       goto abort;
  239.  
  240.    /* fill in the struture with what we are dealing with */
  241.    timerreq->tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
  242.    timerreq->tr_node.io_Message.mn_Node.ln_Pri = 0;
  243.    timerreq->tr_node.io_Message.mn_ReplyPort =
  244.        &(((struct Process *)FindTask(NULL))->pr_MsgPort);
  245.  
  246.    /* and open us a timer.  Note that we are using VBLANK since it is the */
  247.    /* lowest system overhead.  We are not critical on the timing and only */
  248.    /* want to run as often as possible without killing the system */
  249.    if (OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest*)timerreq, 0))
  250.       goto abort;
  251.  
  252.    /* let our assembler stub squirel away a copy of the low memory */
  253.    SaveMem();
  254.  
  255.    while(1)
  256.       {
  257.       /* see if they asked us to change the interval */
  258.       if ((msg = (struct OURMSG *)GetMsg(port)) != NULL)
  259.          {
  260.          interval = msg->interval;
  261.          FreeMem((char *)msg, msg->msgpart.mn_Length);
  262.          if (interval < 0) goto done;
  263.          }
  264.  
  265.       /* Use the timer to wait our required number of seconds */
  266.       timerreq->tr_node.io_Command = TR_ADDREQUEST;
  267.       timerreq->tr_time.tv_secs =  0;           /* seconds */
  268.       timerreq->tr_time.tv_micro = interval;    /* micro seconds */
  269.       DoIO(timerreq);
  270.  
  271.       /* Now have our buddy check and fix any memory */
  272.       /* if something was wrong, he will tell us about it */
  273.       if (ValidateMem(&rslt))
  274.          {
  275.          /* format the failure data to be displayed */
  276.          *(long *)(&AlertString[CHAR_OFF]) = rslt.data;
  277.  
  278.          /* replace any nulls so they don't screw up the message */
  279.          for (i=CHAR_OFF; i<CHAR_OFF+4; i++)
  280.             if (!AlertString[i]) AlertString[i] = '.';
  281.  
  282.          /* format the address for them */
  283.          p = &AlertString[ADDR_OFF+7];
  284.          v = rslt.address;
  285.          for (i = 7; i>= 0; i--)
  286.             {
  287.             *p-- = "0123456789ABCDEF"[v&15];
  288.             v >>= 4;
  289.             }
  290.  
  291.          /* format the data value for them */
  292.          p = &AlertString[DATA_OFF+7];
  293.          v = rslt.data;
  294.          for (i = 7; i>= 0; i--)
  295.             {
  296.             *p-- = "0123456789ABCDEF"[v&15];
  297.             v >>= 4;
  298.             }
  299.  
  300.          /* put up a requester to indicate it failed */
  301.          if (!DisplayAlert(0xBADC0DE, AlertString, ALERTHEIGHT))
  302.             {
  303.             /* They want us to patch it up for them... */
  304.             *(long *)(rslt.address) = rslt.data;
  305.             SaveMem();     
  306.             }
  307.          }
  308.       }
  309.  
  310. done:
  311.    CloseDevice(timerreq);
  312. abort:
  313.    if (timerreq != NULL) FreeMem ((char *)timerreq, sizeof(struct timerequest));
  314.    if (IntuitionBase != NULL) CloseLibrary((struct Library *)IntuitionBase);
  315.    DeletePort(port);
  316.    XCEXIT(-1);
  317.    }
  318.  
  319. void MemCleanup(){}
  320.  
  321. struct MsgPort *CreatePort(name, pri)
  322. char *name;
  323. int pri;
  324. {
  325.    UBYTE sigbit;
  326.    register struct MsgPort *port;
  327.  
  328.    if ((sigbit = AllocSignal(-1)) == -1)
  329.       return((struct MsgPort *)0);
  330.  
  331.    if ((port = (struct MsgPort *)AllocMem(sizeof(struct MsgPort),
  332.                         MEMF_CLEAR|MEMF_PUBLIC)) == 0)
  333.       {
  334.       FreeSignal(sigbit);
  335.       return((struct MsgPort *) (0));
  336.       }
  337.    port->mp_Node.ln_Name = name;
  338.    port->mp_Node.ln_Pri = pri;
  339.    port->mp_Node.ln_Type = NT_MSGPORT;
  340.    port->mp_Flags = PA_SIGNAL;
  341.    port->mp_SigBit = sigbit;
  342.    port->mp_SigTask = (struct Task *)FindTask(0);
  343.    AddPort(port);
  344.    return(port);
  345. }
  346.  
  347. void DeletePort(port)
  348. struct MsgPort *port;
  349. {
  350. RemPort(port);
  351. FreeSignal(port->mp_SigBit);
  352. FreeMem((char *)port,sizeof(struct MsgPort));
  353. }
  354.